/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once
#include <baja/common.hpp>
#include <journal/views/interfaces.h>
#include <journal/views/animation.hpp>

namespace journal { namespace view {

namespace a = baja::app;

class notebook_camera : 
    public inotebook_camera, 
    public std::enable_shared_from_this<notebook_camera>,
    public ianimation_observer
{
    struct animation_id
    {
        static const int offsetXY = 1;
        static const int scale = 2;
        static const int distance = 3;
        static const int angles = 4;
    };

public:
    static std::shared_ptr<notebook_camera> create(const std::shared_ptr<inotebook_camera_driver>& driver)
    {
        std::shared_ptr<notebook_camera> returnValue = std::make_shared<notebook_camera>(driver);

        std::shared_ptr<ianimation_observer> observer = std::dynamic_pointer_cast<ianimation_observer>(returnValue);

        returnValue->_offsetXYAnimation.setObserver(observer);
        returnValue->_scaleAnimation.setObserver(observer);
        returnValue->_distanceAnimation.setObserver(observer);
        returnValue->_anglesAnimation.setObserver(observer);
        return returnValue;
    }

    notebook_camera(const std::shared_ptr<inotebook_camera_driver>& driver) : 
        _driver(driver),
        _offsetXYAnimation(animation_id::offsetXY),
        _scaleAnimation(animation_id::scale),
        _distanceAnimation(animation_id::distance),
        _anglesAnimation(animation_id::angles),
        _state(notebook_camera_state::idle),
        _offsetXYDelta(0.f, 0.f)
    {
    }

public:
    // inotebook_camera
    void notebook_camera::moveToPage(
        const std::shared_ptr<ipage_layout>& layout, 
        const size_t pageNumber, 
        bool keepY = false, 
        const b::float32 duration = 0.f,
        const m::point2d& acceleration = m::point2d(0.1f, 0.1f)
        );
    void setAngles(
        const m::point3d& angles, 
        const b::float32 duration = 0.f,
        const m::point2d& acceleration = m::point2d(0.1f, 0.1f)
        );
    void setDistance(
        const b::float32 distance, 
        const b::float32 duration = 0.f,
        const m::point2d& acceleration = m::point2d(0.1f, 0.1f)
        );
    void setOffsetXY(
        const m::point2d& offsetXY, 
        const b::float32 duration = 0.f, 
        const m::point2d& acceleration = m::point2d(0.1f, 0.1f),
        const bool delta = false
        );
    void setScale(
        const b::float32 scale, 
        const b::float32 duration = 0.f,
        const m::point2d& acceleration = m::point2d(0.1f, 0.1f)
        );
    void reset(
        const std::shared_ptr<ipage_layout>& layout, 
        const b::float32 duration = 0.f,
        const m::point2d& acceleration = m::point2d(0.1f, 0.1f)
        );
    animation_3d& anglesAnimation() { return _anglesAnimation; }
    animation& distanceAnimation() { return _distanceAnimation; }
    animation& scaleAnimation() { return _scaleAnimation; }
    animation_2d& offsetXYAnimation() { return _offsetXYAnimation; }
    notebook_camera_state state() { return _state; }

    // itick_observer
    void onTick();

    // ianimation_observer
    void onUpdate(const int id);
    void onEnd(const int id);

private:
    void changeState(const notebook_camera_state state);

private:
    notebook_camera_state _state;
    std::shared_ptr<inotebook_camera_driver> _driver;

    animation_2d _offsetXYAnimation;
    animation_3d _anglesAnimation;
    animation _scaleAnimation;
    animation _distanceAnimation;
    m::point2d _offsetXYDelta;
};

inline std::shared_ptr<inotebook_camera> createNotebookCamera(
    const std::shared_ptr<inotebook_camera_driver>& driver
    )
{
    std::shared_ptr<notebook_camera> notebookCamera = notebook_camera::create(driver);
    return std::dynamic_pointer_cast<inotebook_camera>(notebookCamera);
}

}} // namespace journal::view